<?php

namespace app\db\model;

use think\Db;
use think\Model;

class DbTemplateRelationQuestion extends Model
{

    // 开启自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';
    // 定义时间戳字段名
    protected $createTime = 'create_time';
    protected $updateTime = 'update_time';
    protected $dbName     = 'db_template_relation_question';

    # --------------------------------- 查询类接口 START------------------------------------
    /**
     * 获取关联变量信息
     * @param int  $item_id 模块ID
     * @author MSQ 2021-8-2
    **/
    public function getDetails($question_id = 0,$template_id = 0,$field = '')
    {
        $where = [
            'r.question_id' => $question_id,
            'r.template_id' => $template_id,
            'r.status'      => 1,
            'q.status'      => 1,
        ];
        if (!$field) $field = 'r.question_id,q.question_key,q.parent_id,q.create_type,r.question_name,r.weight,r.show_status,q.question_type,q.item_id';
        if ($field && $field != '*' && count(explode(',', $field)) == 1) {
            // 只取一个字段
            $info = db($this->dbName)->alias('r')
                ->join('db_question q',' q.id = r.question_id')
                ->where($where)
                ->value($field);
        }else{
            $info = db($this->dbName)->alias('r')
                ->join('db_question q',' q.id = r.question_id')
                ->field($field)
                ->where($where)
                ->find();
        }
        return $info;
    }
    /**
     * 根据模板id和item_id获取所有问题
     * @param  [type]  $template_id 模板id
     * @param  [type]  $item_id     模块id 可以是数组
     * @param  [type]  $need        need_option:需要问题的选项 need_hide:需要隐藏 need_data:需要初始化回答 病例详情页需要 变量管理页不需要
     * @return [type]               [description]
     * @author MSQ 2021-8-9
     */
    public function getQuestionListByItemId($template_id = 0,$item_id = 0,$need = false)
    {
        if (!$template_id || !$item_id) return [];
        
        if ($need === false) $need = model('DbTemplateRelationQuestion')->getQuestionListAllNeed();

        # 是否需要选项 是否需要隐藏的问题变量
        $need_option = in_array('need_option', $need) ? true : false;
        $need_hide   = in_array('need_hide', $need) ? true : false;
        $need_data   = in_array('need_data', $need) ? true : false;

        # 根据模板id和item_id获取题目
        $where = [
            'r.template_id' => $template_id,
            'q.status'      => 1,//未删除
            'r.status'      => 1,
        ];
        if (!$need_hide) $where['r.show_status'] = 1;//不需要隐藏变量

        if (is_array($item_id)) {
            $where['q.item_id'] = ['IN',$item_id];
        } else {
            $where['q.item_id'] = $item_id;
        }

        $field = 'r.id as relation_id,r.question_id,r.question_name,q.question_key,r.weight,r.show_status,r.template_id,q.item_id,q.parent_id,q.question_type,q.input_placeholder,q.question_unit,q.question_describe,q.create_type,q.create_time';
        # 获取所有问题数据
        $questionList = db($this->dbName)->alias('r')
            ->join('db_question q','q.id = r.question_id')
            ->field($field)
            ->where($where)
            ->order('r.weight DESC,q.weight DESC,q.id ASC')
            ->select();
        if (!$questionList) return [];

        if ($need_option) {//需要问题的选项
            $questionIds = array_column($questionList, 'question_id');
            # 根据模板id和question_id获取所有选项
            $questionOptionList = model('DbTemplateRelationQuestionOption')->getOptionListByQId($template_id,$questionIds,'',false);
            # 题目id=>选项列表
            $questionOptionList = arrayGroupByKey($questionOptionList,'question_id');
        }
        # 上级题目id=>题目列表
        $questionList = arrayGroupByKey($questionList,'parent_id');
        if (!$questionList[0]) return [];
        # 初始化需要返回的问题列表
        $returnQuestionList = [];
        # 记录返回key
        $i = 0;
        # 初始化回答
        $initAnswerDataArr = [
            'db_data_id'   => [],
            'answer_value' => [],
        ];
        $initAnswerDataStr = [
            'db_data_id'   => 0,
            'answer_value' => '',
        ];
        foreach ($questionList[0] as $k_q => $v_q) {
            # 把对应的一级问题加到返回值
            $returnQuestionList[$i] = $v_q;
            if ($v_q['question_type'] == 0) {
                $returnQuestionList[$i]['child_question'] = [];
                
                if (!@$questionList[$v_q['question_id']]) {
                    # $i+1 避免没有子变量的变量组被覆盖不返回
                    $i++;
                    continue;
                }
                # 有二级问题
                $j = 0;
                # 循环二级问题
                foreach ($questionList[$v_q['question_id']] as $k_q_a => $v_q_a) {

                    # 初始化回答
                    if ($need_data) {
                        $v_q_a['answer_data'] = $initAnswerDataStr;
                        if (in_array($v_q_a['question_type'],[1,2])) $v_q_a['answer_data'] = $initAnswerDataArr;
                    }

                    if ($need_option && isset($questionOptionList[$v_q_a['question_id']]) && $questionOptionList[$v_q_a['question_id']]) {
                        # 需要选项且对应问题有选项列表
                        $v_q_a['option_list'] = $questionOptionList[$v_q_a['question_id']];
                    }
                    # 将一级变量下的二级变量放入数组
                    $returnQuestionList[$i]['child_question'][$j++] = $v_q_a;
                }
            } else {
                # 初始化回答
                if ($need_data) {
                    $returnQuestionList[$i]['answer_data'] = $initAnswerDataStr;
                    if (in_array($v_q['question_type'],[1,2])) $returnQuestionList[$i]['answer_data'] = $initAnswerDataArr;
                }

                # 没有二级问题，需要问题的选项，则看当前题目是否有选项，有则对应
                if ($need_option && isset($questionOptionList[$v_q['question_id']]) && $questionOptionList[$v_q['question_id']]) {
                    # 将选项加入到返回数组下的问题数组里面
                    $returnQuestionList[$i]['option_list'] = $questionOptionList[$v_q['question_id']];
                }
            }
            $i++;
        }        
        # 一级问题排序
        array_multisort(array_column($returnQuestionList, 'weight'), SORT_DESC, array_column($returnQuestionList, 'relation_id'), SORT_ASC, $returnQuestionList);

        return $returnQuestionList;
    }
    /**
     * 检测模板与变量是否已关联
     * @param  [type] $template_id 模板id
     * @param  [type] $question_id 变量id
     * @author MSQ 2021-8-11
     */
    public function checkExistRelationQuestion($template_id = 0,$question_id = 0,$field = '*')
    {
        if (!$template_id || !$question_id) return [];
        $where = [
            'template_id' => $template_id,
            'status'      => 1,
        ];
        if (is_array($question_id)) {
            $where['question_id'] = ['IN',$question_id];

            if ($field && $field != '*' && count(explode(',', $field)) == 1) {
                // 只取一个字段
                $info = $this->where($where)->column('question_id,'.$field);
            }else{
                $info = db($this->dbName)->field($field)->where($where)->select();
            }
        }else{
            $where['question_id'] = $question_id;

            if ($field && $field != '*' && count(explode(',', $field)) == 1) {
                // 只取一个字段
                $info = $this->where($where)->value($field);
            }else{
                $info = db($this->dbName)->field($field)->where($where)->find();
            }
        }
        if (!$info) return [];
        return $info;
    }
    /**
     * 检测所选模板下 parent_id下是否已有同名的item存在
     * @param  [type] $template_id    模板id
     * @param  [type] $question_name  变量名称
     * @param  [type] $item_id        所属模块id
     * @param  [type] $parent_id      上级id 可为0
     * @param  [type] $ignore_id      需要忽略的question_id（如编辑时不需要检测跟自己重复）
     * @param  [type] $question_type  变量类型 允许同名不同类型
     * @return [type]                 [description]
     * @author MSQ  2021-8-16
     */
    public function checkQuestionExistByQuestionName($template_id = 0,$question_name = '',$item_id = 0,$parent_id = 0,$ignore_id = 0,$question_type = 0)
    {
        if (!$template_id || !$question_name || !$item_id) return false;
         $where = [
            'r.template_id'   => $template_id,
            'q.item_id'       => $item_id,
            'q.parent_id'     => $parent_id,
            'r.question_name' => $question_name,
            'q.question_type' => $question_type,
            'q.status'        => 1,//未删除
            'r.status'        => 1,//未删除
        ];
        if ($ignore_id && is_array($ignore_id)) {
            $where['r.question_id'] = ['NOT IN',$ignore_id];
        } elseif ($ignore_id && $ignore_id) {
            $where['r.question_id'] = ['NEQ',$ignore_id];
        }
        # 检测当前模板当前模块下是否已经有一样的item
        $checkExist = db($this->dbName)->alias('r')
            ->join('db_question q','q.id = r.question_id')
            ->field('r.id as relation_id,r.item_id,r.question_name,q.parent_id,r.question_id')
            ->where($where)
            ->find();
        return $checkExist;
    }
    /**
     * 获取关联模板模块下变量列表 
     * 与getQuestionListByItemId类似但返回数据没那么复杂
     * @param  [type] $template_id    模板id
     * @param  [type] $item_id        模块ID
     * @return [type]                 [description]
     * @author MSQ  2021-8-17
     */
    public function getQuestionByItemId($item_id = 0,$template_id = 0,$field = '')
    {
        if (!$template_id || !$item_id) return false;
        
        if (!is_array($item_id)) $item_id = [$item_id];

        $where = [
            'r.template_id' => $template_id,
            'q.item_id'     => ['IN',$item_id],
            'q.status'      => 1,//未删除
            'r.status'      => 1,
        ];
        if (!$field) $field = 'q.question_key,q.parent_id,q.question_type,q.item_id,r.question_name,r.question_id';
        if ($field && $field != '*' && count(explode(',', $field)) == 1) {
            // 只取一个字段
            $info = db($this->dbName)->alias('r')
                ->join('db_question q','q.id = r.question_id')
                ->where($where)
                ->column($field);
        }else{
            $info = db($this->dbName)->alias('r')
                ->field($field)
                ->join('db_question q','q.id = r.question_id')
                ->where($where)
                ->select();
        }
        return $info;
    }
    /**
     * 获取关联模板变量组下二级变量 
     * @param  [type] $template_id    模板id
     * @param  [type] $item_id        模块ID
     * @return [type]                 [description]
     * @author MSQ  2021-8-17
     */
    public function getChildQuestionByPid($question_id = 0,$template_id = 0,$field = '')
    {
        if (!$template_id || !$question_id) return [];
        if (!is_array($question_id)) $question_id = [$question_id];

        $where = [
            'r.template_id' => $template_id,
            'q.parent_id'   => ['IN',$question_id],
            'q.status'      => 1,//未删除
            'r.status'      => 1,
        ];
        if (!$field) $field = 'q.id,q.question_key,q.parent_id,q.question_type,q.item_id,r.question_name';
        if ($field && $field != '*' && count(explode(',', $field)) == 1) {
            // 只取一个字段
            $info = db($this->dbName)->alias('r')
                ->join('db_question q','q.id = r.question_id')
                ->where($where)
                ->column($field);
        }else{
            $info = db($this->dbName)->alias('r')
                ->field($field)
                ->join('db_question q','q.id = r.question_id')
                ->where($where)
                ->select();
        }
        return $info;
    }
    /**
     * 获取模板下所有关联变量
     * @param [type] $template_id 模板id
     * @author MSQ   2021-8-24
     */
    public function getQuestionListByTemplateId($template_id = 0,$is_hide = false,$field = '')
    {
        if (!$template_id) return false;

        if (!$field) $field = 'q.id,q.question_key,q.parent_id,q.question_type,q.item_id,r.question_id,r.question_name';
        $where = [
            'r.template_id' => $template_id,
            'r.status' => 1,
            'q.status' => 1,
        ];
        if (!$is_hide) $where['r.show_status'] = 1;

        $list = db($this->dbName)->alias('r')
            ->join('db_question q','q.id = r.question_id')
            ->where($where)
            ->field($field)
            ->select();
        return $list;
    }
    /**
     * 根据模板id及变量id获取变量信息 
     * @param  [type] $template_id    模板id
     * @param  [type] $question_ids   变量id
     * @return [type]                 [description]
     * @author MSQ  2021-8-17
     */
    public function getQuestionByQids($template_id = 0,$question_ids = 0,$is_hide = 0,$field = '')
    {
        if (!$template_id || !$question_ids) return [];
        
        $where = [
            'r.template_id' => $template_id,
            'r.question_id' => ['IN',$question_ids],
            'q.status'      => 1,//未删除
            'r.status'      => 1,
        ];
        if (!$is_hide) $where['r.show_status'] = 1;

        if (!$field) $field = 'r.question_id,q.question_key,q.parent_id,q.create_type,r.question_name,r.weight,r.show_status,q.question_type,q.item_id';
        if ($field && $field != '*' && count(explode(',', $field)) == 1) {
            // 只取一个字段
            $info = db($this->dbName)->alias('r')
                ->join('db_question q','q.id = r.question_id')
                ->where($where)
                ->column($field);
        }else{
            $info = db($this->dbName)->alias('r')
                ->field($field)
                ->join('db_question q','q.id = r.question_id')
                ->where($where)
                ->select();
        }
        return $info;
    }
     /**
     * 递归获取父级变量名-目前没有地方调用 已废弃
     * @param  [type] $template_id 模板id
     * @param  [type] $parent_id   父级id
     * @author MSQ 2021-8-25
     */
    function recursiveGetParQuestionName($template_id = 0,$parent_id = 0,&$names){
        $parQuestionInfo = $this->getDetails($parent_id,$template_id);

        if ($parQuestionInfo){
            if ($names) {
                # 已有上级 拼接上当前变量名
                $names .= '-'.$parQuestionInfo['question_name'];
            }else{
                $names = $parQuestionInfo['question_name'];
            }
            // $names = $names.'-'.$parQuestionInfo['question_name'];
            if ($parQuestionInfo['parent_id']){
                return $this->recursiveGetParQuestionName($parQuestionInfo['parent_id'],$names);
            }
        }
    }
    /**
     * 统计模板变量数
     * @param  [type] $template_id 模板id
     * @author MSQ 2021-9-3
     */
    public function getTemplateQuestionCount($template_id = 0)
    {
        if (!$template_id) return false;
        $where = [
            'r.status' => 1,
            'q.status' => 1,
            'r.template_id'   => $template_id,
            'q.question_type' => ['NEQ',0],//变量组不计入
        ];
        $count = db($this->dbName)->alias('r')
                ->join('db_question q',' q.id = r.question_id')
                ->where($where)
                ->count();
        return $count;
    }
    /**
     * 根据need获取变量列表cache的key
     * @param  [type] $template_id 模板id
     * @param  [type] $item_id 模块id
     * @param  [type] $need 需要的参数
     * @author MSQ 2021-9-6
     */
    public function getQuestionListCacheKey($template_id = 0,$item_id = 0,$need = false)
    {
        if (!$template_id || !$item_id) return false;
        if ($need === false) $need = $this->getQuestionListAllNeed();

        $need_question = in_array('need_question', $need) ? 1 : 0;
        $need_option = in_array('need_option', $need) ? 1 : 0;
        $need_hide = in_array('need_hide', $need) ? 1 : 0;
        $need_data = in_array('need_data', $need) ? 1 : 0;

        $cacheKey = 'question_list_'.$template_id.'_'.$item_id.'_'.$need_question.'_'.$need_option.'_'.$need_hide.'_'.$need_data;

        return $cacheKey;
    }
    /**
     * 获取变量列表所有need
     * @author MSQ 2021-9-6
     */
    public function getQuestionListAllNeed()
    {
        $need = ['need_question','need_option','need_hide','need_data'];

        return $need;
    }
    /**
     * 根据变量id获取变量信息并排序
     * 适用于导出病例时对变量进行排序
     * 从二级变量找到一级目录，再根据一级目录排序一步步往下找
     * @author MSQ 2021-10-21
     */
    public function getWeightSortForExport($template_id = 0,$question_ids = [])
    {
        if (!$template_id || !$question_ids) return [];
        
        $questionField = 'r.id relation_id,r.question_id,q.question_key,q.parent_id,r.question_name,r.weight,q.question_type,q.item_id';

        # 基本信息相关变量id 基本信息变量固定在最前面
        $baseItemId = model('DbItem')->getBasicItemInfo('id');
        $baseQids = model("DbTemplateRelationQuestion")->getQuestionByItemId($baseItemId,$template_id,'q.id');
        # 取交集 即要导出的基本信息变量 不参与排序固定在最前面的变量
        $expordBaseQids = array_intersect($question_ids,$baseQids);
        # 取差集 即要导出的非基本信息变量 参与排序的变量
        $question_ids = array_diff($question_ids,$baseQids);
        # 获取导出基本信息变量数据
        $baseQuestion = model("DbTemplateRelationQuestion")->getQuestionByQids($template_id,$expordBaseQids,0,$questionField);
        # 基本信息排序
        array_multisort(array_column($baseQuestion, 'weight'), SORT_DESC, array_column($baseQuestion, 'relation_id'), SORT_ASC, $baseQuestion);
        $returnData = $baseQuestion;

        # 对应变量列表
        $questionList = model("DbTemplateRelationQuestion")->getQuestionByQids($template_id,$question_ids,0,$questionField);
        if (!$questionList) return $returnData;

        $questionGroup = arrayGroupByKey($questionList,'parent_id');
        # 一级变量
        $topQuestion = isset($questionGroup[0]) ? $questionGroup[0] : [];

        # 变量组列表 参与排序但不参与数据返回(变量组没有回答)
        $parQids = array_filter(array_unique(array_column($questionList,'parent_id')));
        $parentQuestionList = $this->getQuestionByQids($template_id,$parQids,0,$questionField);
        # 所有变量
        $allQuestionLists = array_merge($questionList,$parentQuestionList);
        # 所有顶级变量 一级变量+变量组
        $topQuestionList = array_merge($topQuestion,$parentQuestionList);

        $topQuestionGroup = arrayGroupByKey($topQuestionList,'item_id');

        $itemField = 'r.id relation_id,r.item_id,i.parent_id,i.type,i.classify_rank,r.item_name,r.weight';

        # 二级模块列表
        $itemIds = array_unique(array_column($questionList,'item_id'));
        if (!$itemIds) return $returnData;

        $itemList = model('DbTemplateRelationItem')->getDetails($itemIds,$template_id,$itemField);
        if (!$itemList) return $returnData;
        $itemGroup = arrayGroupByKey($itemList,'parent_id');

        # 一级模块列表
        $parItemIds = array_unique(array_column($itemList,'parent_id'));
        if (!$parItemIds) return $returnData;

        $parItemList = model('DbTemplateRelationItem')->getDetails($parItemIds,$template_id,$itemField);
        if (!$parItemList) return $returnData;
        $parItemGroup = arrayGroupByKey($parItemList,'parent_id');
        
        # 二级目录列表
        $dirIds = array_unique(array_column($parItemList,'parent_id'));
        if (!$dirIds) return $returnData;

        $dirList = model('DbTemplateRelationItem')->getDetails($dirIds,$template_id,$itemField);
        if (!$dirList) return $returnData;

        # 没有上级的二级目录 即顶级目录
        $dirGroup = arrayGroupByKey($dirList,'parent_id');
        $topSecondDir = isset($dirGroup[0]) ? $dirGroup[0] : [];

        # 一级目录列表
        $pardirIds = array_filter(array_unique(array_column($dirList,'parent_id')));
        $pardirList = model('DbTemplateRelationItem')->getDetails($pardirIds,$template_id,$itemField);
        # 顶级目录 没有父级的二级目录+一级目录
        $topDirList = array_merge($topSecondDir,$pardirList);

        # 一级目录排序
        array_multisort(array_column($topDirList, 'weight'), SORT_DESC, array_column($topDirList, 'relation_id'), SORT_ASC, $topDirList);
        # 循环一级目录
        foreach ($topDirList as $key1 => $value1) {
            # 判断当前目录是一级目录还是二级目录
            if (in_array($value1['item_id'],$dirIds)) {
                # 二级目录
                $this->getWeightSortForExportDir($returnData,$value1['item_id'],$parItemGroup,$itemGroup,$topQuestionGroup,$questionGroup);
            }else{
                # 一级目录
                # 该目录下二级目录
                $secondDir = $dirGroup[$value1['item_id']];
                # 二级目录排序
                array_multisort(array_column($secondDir, 'weight'), SORT_DESC, array_column($secondDir, 'relation_id'), SORT_ASC, $secondDir);
                # 循环二级目录
                foreach ($secondDir as $key2 => $value2) {

                    $this->getWeightSortForExportDir($returnData,$value2['item_id'],$parItemGroup,$itemGroup,$topQuestionGroup,$questionGroup);
                }
            }
        }

        return $returnData;
    }
    /**
     * 根据变量id获取变量信息并排序-续
     * 该方法封装从目录id找到变量id
     * @author MSQ 2021-10-21
     */
    public function getWeightSortForExportDir(&$returnData = [],$item_id = 0,$parItemGroup = [],$itemGroup = [],$topQuestionGroup = [],$questionGroup = [])
    {
        # 该目录下一级模块
        $firstItemList = $parItemGroup[$item_id];
        if (!$firstItemList) return $returnData;
        # 一级模块排序
        array_multisort(array_column($firstItemList, 'weight'), SORT_DESC, array_column($firstItemList, 'relation_id'), SORT_ASC, $firstItemList);
        # 循环一级模块
        foreach ($firstItemList as $key1 => $value1) {
            # 该一级模块下二级模块
            $secondItemList = $itemGroup[$value1['item_id']];
            if (!$secondItemList) return $returnData;

            # 二级模块排序
            array_multisort(array_column($secondItemList, 'weight'), SORT_DESC, array_column($secondItemList, 'relation_id'), SORT_ASC, $secondItemList);
            # 循环二级模块
            foreach ($secondItemList as $key2 => $value2) {
                # 该二级模块下变量组/一级变量
                $firstQuestionList = $topQuestionGroup[$value2['item_id']];
                if (!$firstQuestionList) return $returnData;

                # 变量组/一级变量排序
                array_multisort(array_column($firstQuestionList, 'weight'), SORT_DESC, array_column($firstQuestionList, 'relation_id'), SORT_ASC, $firstQuestionList);
                # 循环变量组/一级变量
                foreach ($firstQuestionList as $key3 => $value3) {
                    # 是否是变量组
                    if (!$value3['question_type']) {
                        # 变量组
                        # 获取变量组下二级变量
                        $secondQuestionList = $questionGroup[$value3['question_id']];
                        if (!$secondQuestionList) return $returnData;

                        # 二级变量排序
                        array_multisort(array_column($secondQuestionList, 'weight'), SORT_DESC, array_column($secondQuestionList, 'relation_id'), SORT_ASC, $secondQuestionList);
                        # 添加到返回数据
                        $returnData = array_merge($returnData,$secondQuestionList);
                    }else{
                        # 一级变量
                        # 添加到返回数据
                        $returnData = array_merge($returnData,[$value3]);
                    }
                }
            }
        }
        return $returnData;
    }
    # ---------------------------------- 查询类接口 END-------------------------------------

    # ------------------------------- 数据处理类接口 START ----------------------------------
    /**
     * 根据模板ID生成question关联
     * 适用于创建总库引用模板-生成模块后同步生成变量及选项
     * @param [type] $origin_template_id 来源模板id 用于读取原模板变量及选项
     * @param [type] $template_id        需要生成关联的模板id
     * @param [type] $database_id        需要生成关联的数据库id
     * @param [type] $origin_item_id     来源模块id 用于读取原模板变量及选项
     * @param [type] $item_id            新生成的模块id
     * @param [type] $basicItemIds       基础信息相关模块id 主表不新增仅新增引用表
     * @param [type] $usercare_id        医务id
     * @author MSQ   2021-9-2
     */
    public function syncQuestionByItemIdForQuoteTemplate($origin_template_id = 0,$template_id = 0,$database_id = 0,$origin_item_id = 0,$item_id = 0,$basicItemIds = [],$usercare_id = 0)
    {
        if (!$origin_item_id || !$item_id) return false;
        if (!$origin_template_id || !$template_id || !$database_id) return false;
        set_time_limit(0);
        ini_set('memory_limit', '-1');

        # 原模板该模块下变量        
        $field = '
            q.id,q.question_name,q.question_key,q.question_type,q.question_unit,
            q.input_placeholder,q.question_describe,q.weight,q.parent_id,q.create_type,
            r.question_name question_name2,r.weight relation_weight,r.show_status';
        $relationList = $this->getQuestionByItemId($origin_item_id,$origin_template_id,$field);
        $relationList = arrayGroupByKey($relationList,'parent_id');
        if (!@$relationList[0]) return false;

        # 主表是否需要添加
        $isNeedAdd = true;
        # 子库及基础信息相关无需添加
        if (in_array($origin_item_id,$basicItemIds)) $isNeedAdd = false;
        # 公共参数
        $param['item_id'] = $item_id;
        $param['origin_template_id'] = $origin_template_id;
        $param['template_id'] = $template_id;
        $param['database_id'] = $database_id;
        $param['usercare_id'] = $usercare_id;
        $param['isNeedAdd']   = $isNeedAdd;

        $relationQuestionData = $relationOptionData = [];
        # 处理所有一级变量 变量组
        foreach ($relationList[0] as $key => $value) {
            # 同步生成变量及选项 含主表和引用表
            $question_id = $this->syncQuestionAndOptionDataForQuoteTemplate($param,$value,$relationQuestionData,$relationOptionData);
            if (!$question_id) return false;

            # 处理二级变量
            if (@$relationList[$value['id']]) {
                # 同步生成变量及选项 含主表和引用表
                foreach ($relationList[$value['id']] as $key2 => $value2) {
                    $value2['parent_id'] = $question_id;
                    $questionId = $this->syncQuestionAndOptionDataForQuoteTemplate($param,$value2,$relationQuestionData,$relationOptionData);
                    if (!$questionId) return false;
                }
            }
        }
        # 批量新增关联变量
        $relationQuestionData = array_chunk($relationQuestionData, 1000);
        foreach ($relationQuestionData as $key => $value) {
            $this->setAttr('id',null)->isUpdate(false)->saveAll($value);
            // $this->saveAll($value);
        }
    
        # 批量新增关联选项
        $relationOptionData = array_chunk($relationOptionData, 1000);
        foreach ($relationOptionData as $key => $value) {
            // model('DbTemplateRelationQuestionOption')->saveAll($value);
            model('DbTemplateRelationQuestionOption')->setAttr('id',null)->isUpdate(false)->saveAll($value);
        }
        
        return true;
    }
     /**
     * 引用模板时同步生成变量及选项
     * 适用于引用模板-生成模块后同步生成变量及选项
     * 为避免频繁连接数据库 该方法只新增主表 组装关联数据批量新增
     * @param [type] $param 相关参数 
     * @param [type] $questionData         变量信息 
     * @param [type] $relationQuestionData 需要同步添加的变量关联数据
     * @param [type] $relationOptionData   需要同步添加的选项关联数据
     * @author MSQ   2021-9-2
     */
    public function syncQuestionAndOptionDataForQuoteTemplate($param = [],$questionData = [],&$relationQuestionData = [],&$relationOptionData = [])
    {
        if (!$param || !$questionData) return false;

        $question_id = $questionData['id'];
        if ($param['isNeedAdd']) {
            # 需要添加主表 基础信息相关变量及子库无需添加仅添加关联即可
            $addQuestion = [
                'item_id'           => $param['item_id'],
                'question_name'     => $questionData['question_name'],
                'parent_id'         => $questionData['parent_id'],
                'question_key'      => $questionData['question_key'].'&'.uniqid(),
                'question_type'     => $questionData['question_type'],
                'question_unit'     => $questionData['question_unit'],
                'input_placeholder' => $questionData['input_placeholder'],
                'question_describe' => $questionData['question_describe'],
                'weight'            => $questionData['weight'],
                'create_type'       => $questionData['create_type'],
                'template_id'       => $param['template_id'],
                'database_id'       => $param['database_id'],
                'usercare_id'       => $param['usercare_id'],
            ];
            $question_id = model('DbQuestion')->addData($addQuestion);
        }
        # 组装变量关联数据
        $relationQuestionData[] = [
            'question_id'   => $question_id,
            'item_id'       => $param['item_id'],
            'question_name' => $questionData['question_name2'],
            'database_id'   => $param['database_id'],
            'template_id'   => $param['template_id'],
            'weight'        => $questionData['relation_weight'],
            'show_status'   => $questionData['show_status'],
        ];

        # 处理选项
        if (in_array($questionData['question_type'],[1,2,3])) {
            # 获取变量下选项
            $field = 'o.*,r.option_name option_name2,r.weight relation_weight,r.show_status';
            $optionList = model('DbTemplateRelationQuestionOption')->getOptionListByQId($param['origin_template_id'],$questionData['id'],$field);
            foreach ($optionList as $optionK => $optionV) {
                $option_id = $optionV['id'];
                if ($param['isNeedAdd']) {
                    # 总库且非基础信息相关选项 同步新增主表选项
                    $addOption = [
                        'option_name' => $optionV['option_name'],
                        'option_key'  => $optionV['option_key'].'&'.uniqid(),
                        'question_id' => $question_id,
                        'is_other'    => $optionV['is_other'],
                        'weight'      => $optionV['weight'],
                        'template_id' => $param['template_id'],
                    ];
                    $option_id = model('DbQuestionOption')->addData($addOption);
                }
                # 组装选项关联数据
                $relationOptionData[] = [
                    'question_id' => $question_id,
                    'option_id'   => $option_id,
                    'option_name' => $optionV['option_name2'],
                    'database_id' => $param['database_id'],
                    'template_id' => $param['template_id'],
                    'weight'      => $optionV['relation_weight'],
                    'show_status' => $optionV['show_status'],
                ];
            }
        }
        return $question_id;
    }
    /**
     * 根据模板ID生成question关联
     * 适用于创建子库-引用模板
     * @param [type] $origin_template_id 来源模板id
     * @param [type] $template_id        需要生成关联的模板id
     * @param [type] $database_id        需要生成关联的数据库id
     * @author MSQ   2021-8-3
     */
    public function addTemplateRelationQuestionByTemplateId($origin_template_id = 0,$template_id = 0,$database_id = 0,$where_ori = [])
    {
        if (!$origin_template_id || !$template_id || !$database_id) return false;

        if (!$where_ori) {
            # 无自定义where
            $where_ori = [
                'template_id' => $origin_template_id
            ];
        }
        # 固定查询status
        $where_ori['status'] = 1;

        # 原模板关联的question
        $relationList = db($this->dbName)->where($where_ori)->select();
        if (!$relationList) return true;

        $newRelationList = array_chunk($relationList,1000);
        foreach ($newRelationList as $k_a => $v_a) {
            $addTemplateRelationData = [];
            foreach ($v_a as $k_b => $v_b) {
                $addTemplateRelationData[] = [
                    'template_id'   => $template_id,
                    'database_id'   => $database_id,
                    'item_id'       => $v_b['item_id'],
                    'question_id'   => $v_b['question_id'],
                    'question_name' => $v_b['question_name'],
                    'weight'        => $v_b['weight'],
                    'show_status'   => $v_b['show_status'],
                ];
            }
            // $res = $this->saveAll($addTemplateRelationData);
            $res = $this->setAttr('id',null)->isUpdate(false)->saveAll($addTemplateRelationData);
            if (!$res) return false;
        }
        return true;
    }
    /**
     * 创建关联变量
     * @param [type] $template_id 模板id
     * @param [type] $question_id 变量id
     * @author MSQ   2021-8-12
     */
    public function createRelationQuestion($data = [])
    {        
        if ( (!isset($data['question_id']) || !$data['question_id']) || (!isset($data['template_id']) || !$data['template_id']) || (!isset($data['item_id']) || !$data['item_id'])) return false;
        if (!isset($data['database_id'])) $data['database_id'] = model('DbTemplate')->getDetails($data['template_id'],'database_id');
        if (!$data['database_id']) return false;
        
        $questionInfo = model('DbQuestion')->getDetails($data['question_id']);
        if (!$questionInfo) return false;

        $isRelation = $this->checkExistRelationQuestion($data['template_id'],$data['question_id']);
        if ($isRelation) return $isRelation['id'];
        
        $addData = [
            'database_id'   => $data['database_id'],
            'template_id'   => $data['template_id'],
            'item_id'       => $data['item_id'],
            'question_id'   => $data['question_id'],
            'question_name' => isset($data['question_name']) ? $data['question_name'] : $questionInfo['question_name'],
            'weight'        => isset($data['weight']) ? $data['weight'] : $questionInfo['weight'],
            'show_status'   => isset($data['show_status']) ? $data['show_status'] : 1,
            // 'parent_id'     => isset($data['parent_id']) ? $data['parent_id'] : 0,
        ];
        $this->setAttr('id',null)->isUpdate(false)->save($addData);
        if (!isset($this->id)) return false;

        if (in_array($questionInfo['question_type'],[1,2,3])) {
            # 新增关联选项
            $optionRes = model('DbTemplateRelationQuestionOption')->createRelationOption($data['question_id'],$data['template_id']);
            if (!$optionRes) return false;
        }
        return $this->id;
              
    }
    /**
     * 编辑变量
     * @param [type] $template_id 模板id
     * @param [type] $question_id 变量id
     * @author MSQ   2021-8-12
     */
    public function saveQuestion($template_id = 0,$question_id = 0,$data = [],$usercare_id = 0)
    {
        if (!$data) return true;
        if (!$template_id || !$question_id) return false;

        if (!isset($data['item_id']) || !$data['item_id'] || !isset($data['question_name']) || !$data['question_name'] || !isset($data['question_type']) || !in_array($data['question_type'], [0,1,2,3,4,5,6,7]) ) return false;
        # 二级变量question_type不能为0
        if (@$data['parent_id'] && !$data['question_type']) return false;

        if (in_array($data['question_type'],[1,2,3]) && (!isset($data['option_list']) || !$data['option_list'])) return false;//单选//多选//下拉 必须要有选项

        $field = 'r.question_id,q.parent_id,r.question_name,q.question_name as question_name_q,r.weight,r.show_status,q.question_type,r.item_id,q.input_placeholder,q.question_unit,q.question_describe';
        $questionInfo = $this->getDetails($question_id,$template_id,$field);
        if (!$questionInfo) return false;

        # 组装更新数据
        $saveRelationData = [];
        $saveChildRelationData = [];
        $saveData = [];
        if (isset($data['question_name']) && $data['question_name'] != $questionInfo['question_name']) {
            $saveRelationData['question_name'] = $data['question_name'];
            $saveChildRelationData['question_name'] = $data['question_name'];
            $saveData['question_name'] = $data['question_name'];
        }
        if (isset($data['show_status']) && $data['show_status'] != $questionInfo['show_status']) {
            $saveRelationData['show_status'] = $data['show_status'];
        }
        if (isset($data['weight']) && $data['weight'] != $questionInfo['weight']) {
            $saveRelationData['weight'] = $data['weight'];
        }
        if (isset($data['parent_id']) && $data['parent_id'] != $questionInfo['parent_id']) {
            $saveData['parent_id'] = $data['parent_id'];
            // $saveChildRelationData['parent_id'] = $data['parent_id'];
        }
        if (isset($data['item_id']) && $data['item_id'] != $questionInfo['item_id']) {
            $saveData['item_id'] = $data['item_id'];
            // $saveChildRelationData['item_id'] = $data['item_id'];
        }
        # 总库下引用该变量的子库模板
        $childTemplateId = model('DbTemplate')->getChildDbOrTemplate($template_id,2,0);
        $childTemplateId = array_filter($childTemplateId);

        # 更新关联表数据
        if ($saveRelationData) {
            # 更新当前数据关联变量
            $where = ['question_id' => $question_id,'template_id' => $template_id,'status' => 1];
            $saveRelationRes = $this->update($saveRelationData,$where);
            if ($saveRelationRes === false) return false;

            $relevantTemplateId = [$template_id];
            # 更新子模板关联变量
            if ($saveChildRelationData && $childTemplateId) {
                $where['template_id'] = ['IN',$childTemplateId];
                $saveRes = $this->update($saveChildRelationData,$where);
                if ($saveRes === false) return false;
                $relevantTemplateId = $relevantTemplateId+$childTemplateId;
            }
        }
        # 是否有跨总库模板引用该变量 目前是一个总库对应一套变量 不存在跨总库一说 且变量类型是可更改的 若是只改关联表的话数据将不同步
        /*$where['template_id'] = ['NOT IN',$relevantTemplateId];
        $isOtherSync = $this->where($where)->value('id');*/
        // if (!$isOtherSync) {
            /*if (isset($saveRelationData['question_name']) && $saveRelationData['question_name'] != $questionInfo['question_name_q']) {
                $saveData['question_name'] = $saveRelationData['question_name'];
            }*/
            if (isset($data['question_type']) && $data['question_type'] != $questionInfo['question_type']) {
                $saveData['question_type'] = $data['question_type'];
            }
            if (isset($data['question_unit']) && $data['question_unit'] != $questionInfo['question_unit']) {
                $saveData['question_unit'] = $data['question_unit'];
            }
            if (isset($data['input_placeholder']) && $data['input_placeholder'] != $questionInfo['input_placeholder']) {
                $saveData['input_placeholder'] = $data['input_placeholder'];
            }
            if (isset($data['question_describe']) && $data['question_describe'] != $questionInfo['question_describe']) {
                $saveData['question_describe'] = $data['question_describe'];
            }
            # 更新变量总表数据
            if ($saveData) {
                $saveRes = model('DbQuestion')->update($saveData,['id' => $question_id,'status' => 1]);
                if (!$saveRes) return false;
            }
        // }
        
        # 处理选项
        # 获取原本选项
        $oldOption = model('DbQuestionOption')->getQuestionOptionByQid($question_id);
        $oldOption = $beforeOption = array_column($oldOption,NULL,'id');
        if (!@$data['option_list']) $data['option_list'] = [];
        foreach ($data['option_list'] as $key => $value){
            # 保留编辑后仍然存在的选项
            if($value['option_id'] && isset($beforeOption[$value['option_id']])) unset($beforeOption[$value['option_id']]);
        }
        $deleteOptions = array_keys($beforeOption);
        # 删除选项 原本有 编辑后没有的 若是由选择题、下拉框改为输入框则全删
        if($deleteOptions){
            # 删除选项及关联选项
            $optionSaveRes = model('DbQuestionOption')->deleteOptions($deleteOptions,$template_id);
            if($optionSaveRes === false) return false;
        }      
        # 选择题、下拉列表题，处理新的或改动后的选项
        if (in_array($data['question_type'],[1,2,3])) {
            $createOptionIds = [];
            # 处理新的选项
            $optionCount = count($data['option_list']);
            foreach ($data['option_list'] as $key => $option){
                $optionData = [];
                if(empty($option['option_id'])){
                    $option_key = isset($option['option_key']) && $option['option_key'] ? $option['option_key'].'&'.uniqid() : model('DbQuestionOption')->getOptionKey($question_id);

                    # 新增选项
                    $optionData['question_id'] = $question_id;
                    $optionData['option_name'] = $option['option_name'];
                    $optionData['is_other']    = $option['is_other'];
                    $optionData['usercare_id'] = $usercare_id;
                    $optionData['template_id'] = $template_id;
                    $optionData['option_key']  = $option_key;
                    $optionData['weight']      = $optionCount;
                    // $optionRes = model('DbQuestionOption')->save($optionData);
                    $optionRes = model('DbQuestionOption')->setAttr('id',null)->isUpdate(false)->save($optionData);
                    if (!isset(model('DbQuestionOption')->id)) return false;
                    # 记录新增的选项id 便于批量新增关联选项
                    $createOptionIds[] = model('DbQuestionOption')->id;
                }else{
                    $oldOptionInfo = $oldOption[$option['option_id']];
                    if (!$oldOptionInfo) return false;
                    # 修改选项
                    $optionData['option_name'] = $option['option_name'];
                    $optionData['is_other']    = $option['is_other'];
                    $optionRes = model('DbQuestionOption')->update($optionData,['id' => $option['option_id'],'status' => 1]);
                    if ($optionRes === false) return false;

                    # 修改关联选项
                    $relationOptionData = [];
                    $relationOptionData['option_name'] = $option['option_name'];
                    $relationOptionData['weight']      = $optionCount;
                    # 变量展示状态发生改变 选项同步发生改变
                    if (isset($saveRelationData['show_status'])) $relationOptionData['show_status'] = $saveRelationData['show_status'];
                    # 目前选项不支持隐藏 只有删除或新增
                    if (isset($option['show_status'])) $relationOptionData['show_status'] = $option['show_status'];
                    $where = [
                        'option_id'   => $option['option_id'],
                        'status'      => 1,
                        'template_id' => $template_id,
                    ];
                    # 更新当前模板关联选项
                    $relationOptionRes = model('DbTemplateRelationQuestionOption')->update($relationOptionData,$where);
                    if ($relationOptionRes === false) return false;

                    # 更新子模板关联选项
                    if ($option['option_name'] != $oldOptionInfo['option_name'] && $childTemplateId) {
                        $where['template_id'] = ['IN',$childTemplateId];
                        $res = model('DbTemplateRelationQuestionOption')->update(['option_name' => $option['option_name']],$where);
                        # 更新有关联想子库
                        if ($res === false) return false;
                    }
                }
                --$optionCount;
            }
            if ($createOptionIds) {
                if (!@$relevantTemplateId) {
                    # 无saveRelationData将会无relevantTemplateId 针对没有更改变量名等信息却更改了选项情况
                    $relevantTemplateId[@$data['database_id']] = $template_id;
                    $relevantTemplateId = $relevantTemplateId+$childTemplateId;
                }
                # 给所有使用该变量的模板添加选项
                foreach ($relevantTemplateId as $key => $value) {
                    $relationOptionRes = model('DbTemplateRelationQuestionOption')->createRelationOptionByOptionIds($createOptionIds,$value,$key);
                    if ($relationOptionRes === false) return false;
                }
            }
        }
        return true;
    }
    /**
     * 删除整个模板下变量
     * @param [type] $template_id 模板id
     * @author MSQ   2021-8-21
     */
    public function deleteDataByTemplate($template_id = [])
    {
        if (!$template_id) return false;
        if (!is_array($template_id)) $template_id = [$template_id];

        $where = [
            'status'      => 1,
            'template_id' => ['IN',$template_id]
        ];
        # 所有要删除的question
        $relevantQuestion = db($this->dbName)->where($where)->group('question_id')->column('question_id');
        if (!$relevantQuestion) return false;

        # 是否有跨总库模板引用该变量
        $where['question_id'] = ['IN',$relevantQuestion];
        $where['template_id'] = ['NOT IN',$template_id];
        # 查找跨总库的question
        $otherSyncQuestion = db($this->dbName)->where($where)->group('question_id')->column('question_id');

        $where = [
            'status'      => 1,
            'template_id' => ['IN',$template_id]
        ];
        # 删除相关模板的关联question
        $res = $this->update(['status' => 0],$where);        
        if (!$res) return false;
        
        # 差集 即没有跨总库引用 可删除总表question
        $deleteQuestions = array_diff($relevantQuestion,$otherSyncQuestion);
        if (!$deleteQuestions) return true;

        $res = model('DbQuestion')->deleteQuestionByIds($deleteQuestions);
        if (!$res) return false;

        return true;
    }
    # --------------------------------- 数据处理类接口 END ----------------------------------

}
